fix: resolve all critical parser and macro issues#70
Merged
dannywillems merged 4 commits intomasterfrom Feb 8, 2026
Merged
Conversation
- Replace broken fragment_nodes/index arithmetic (parent_idx * 1000 + child_idx) with document.root as virtual container, reusing the same navigation as non-fragment mode. Previously silently broke with >1000 children or >2 nesting levels. - Implement proper pop_until that walks open_element_names backwards to find matching tag, instead of the stub that only popped once. - Remove unwrap() calls on open_elements.last() that could panic on malformed input; the refactored code no longer needs them. - Extract navigate_to_element as free function taking &mut Element and &[usize], eliminating the open_elements.clone() on every node insertion. Closes #47, closes #48, closes #49
Previously, for-loop bodies in html! macro silently dropped all children except the first element. Now emits a clear compile error: "for loop body must contain exactly one element". Closes #50
These mapped to types that don't exist in ironhtml-elements, causing confusing compiler errors when used in html! macro. The entries were also identity mappings (no-ops), since to_pascal_case already produces the correct output. Closes #51
28 new tests covering: - pop_until: skips intermediates, no-match preserves root, closes correct level with nested same-tag elements - Fragment nesting: 5 levels deep, text at every level, siblings with children - Fragment void elements: multiple voids, voids between text, voids with attributes, voids nested inside tables - Fragment comments: top-level, inside elements, between siblings - Fragment top-level: text-only, mixed text+elements, empty, whitespace - Malformed input: only end tags, extra end tags, unclosed tags, interleaved tags, deeply mismatched nesting - Full document: head elements, implicit body, implicit head+body, title extraction, round-trip parse
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Parser: rewrite tree builder fragment mode and pop_until — Replace
broken
parent_idx * 1000 + child_idxindex arithmetic with propertree navigation using
document.rootas virtual container. Previouslysilently broke with >1000 children or >2 nesting levels. Implement
proper
pop_untilthat walks the stack backwards instead of the stubthat only popped one element. Remove
unwrap()calls that could panicon malformed input. Also eliminates the
open_elements.clone()onevery node insertion by extracting
navigate_to_elementas a freefunction.
Macro: emit compile error for multi-child for-loops — Previously
for item in #items { li { #item } hr }silently dropped thehr.Now emits: "for loop body must contain exactly one element".
Macro: remove Rb/Rtc from to_pascal_case — These mapped to types
that don't exist in
ironhtml-elements, causing confusing errors.Test plan
elements in fragments, unmatched end tags, pop_until, multiple
top-level fragments)
Closes #47, closes #48, closes #49, closes #50, closes #51